
    /********************************************************/
    /*                                                      */
    /*                                                      */
    /*         Copyright (C), 1993  SEIKO EPSON Corp.       */
    /*         ALL RIGHTS RESERVED                          */
    /*                                                      */
    /*                                                      */
    /*  file name : strtol.c                                */
    /*                                                      */
    /*  Revision history                                    */
    /*      93/12/17    first release       S.Akaiwa        */
    /*      97/2/20	modified	    T.Katahira	    */
    /*			change function declaration	    */
    /*					to the ANSI style   */
    /*                                                      */
    /********************************************************/

#ifdef      UNIX
#include    "stdlib.h"
#include    "limits.h"
#include    "errno.h"
#else
#include    <stdlib.h>
#include    <limits.h>
#include    <errno.h>
#endif

long
strtol(const char * sStrPtrP, char ** sEndPtrP, int iBase)

    /********************************************************/
    /*                                                      */
    /*  The strtol function converts string pointed by      */
    /*  sStrPtrP to long.                                   */
    /*  The address where conversion ended is store in      */
    /*  sEndPtrP.                                           */
    /*  The strtol function returns the converted value.    */
    /*  If nothing is converted, 0 is returns.              */
    /*  LONG_MAX or LONG_MIN is returned, and ERANGE is     */
    /*  stored in errno when overflow is generated.         */
    /*                                                      */
    /*  RETURN  LONG_MAX/LONG_MIN (errno == ERANGE)         */
    /*                  ... Overflow                        */
    /*          Others  ... Converted value                 */
    /*                                                      */
    /********************************************************/

    /* char            * sStrPtrP  ;      pointer to string */
    /* char            **sEndPtrP  ;    convert end pointer */
    /* int             iBase       ;                  radix */
    {

     char           *sStrTmpP;        /* tmp string pointer */
     char           *sStrtPtrP;    /* convert start pointer */
     unsigned long  ulAllDat;                     /* result */
     unsigned long  ulLmtAll;             /* all data limit */
     unsigned long  ulLmtDat;   /* limit of additional data */
     int            iDat;               /* converted a data */
     int            iOvrFlg;               /* overflow flag */
     int            iSign;                     /* sign flag */
     int            iRadix;                        /* radix */

     sStrTmpP = sStrPtrP;
     
     while(*sStrTmpP == ' '){                 /* skip space */
        sStrTmpP++;
     }
                                             /* check radix */
     if((iBase >= 0) && (iBase <= 36)){
        iRadix = iBase;
     }
     else {
        if(sEndPtrP != NULL){
           *sEndPtrP = sStrPtrP;
        } 
        return (long)0;              /* illegal radix value */
     }

     if(*sStrTmpP == '\0'){         /* check convert string */  
        if(sEndPtrP != NULL){
           *sEndPtrP = sStrPtrP;
        }
        return (long)0;            /* string does not exist */
     }

     if(*sStrTmpP == '-'){                 /* get sign flag */
        iSign = -1;
        sStrTmpP++;
     }
     else{
        if(*sStrTmpP == '+'){
           sStrTmpP++;
        }
        iSign = 1;
     }
   
     if((iRadix == 0) || (iRadix == 16)){   /* decide radix */
        if((sStrTmpP[0] == '0') && (toupper(sStrTmpP[1]) == 'X')){
           iRadix = 16;
           sStrTmpP = sStrTmpP + 2;
        }
        else {
           if(iRadix == 0){
              if(*sStrTmpP == '0'){
                 iRadix = 8;
              }
              else {
                 iRadix = 10;
              } 
           }
        }
     }

     sStrtPtrP = sStrTmpP;        /* save convert start ptr */
     ulAllDat = 0L;                  /* clear convert value */
     iOvrFlg = 0;                    /* clear overflow flag */
     ulLmtAll = ULONG_MAX / (unsigned long)iRadix;
              /* make limit value of the data before adding */
     ulLmtDat = ULONG_MAX % (unsigned long)iRadix;
                     /* make limit value of additional data */ 
     
     while(*sStrTmpP != '\0'){        /* convert until '\0' */
        if(isdigit(*sStrTmpP)){
           iDat = *sStrTmpP - '0';
        }
        else {
           if(isalpha(*sStrTmpP)){
              iDat = toupper(*sStrTmpP)-'A'+10;
           }
           else {
              break;
           }
        }

        if(iDat >= iRadix){
           break;                             /* over radix */
        }
        if((ulAllDat > ulLmtAll) || 
            ((ulAllDat == ulLmtAll) && (iDat > ulLmtDat))){
           iOvrFlg = 1;                         /* overflow */
        }
        else {                      /* renew converted data */
           ulAllDat = ulAllDat*(unsigned long)iRadix + 
                                        (unsigned long)iDat;
        }
        sStrTmpP++;                   /* update convert ptr */
     }

     if(sStrtPtrP == sStrTmpP){
        if(sEndPtrP != NULL){
           *sEndPtrP = sStrPtrP;
        }
        return  (long)0;       /* string does not converted */
     }

     if(sEndPtrP != NULL){       /* set convert end address */
        *sEndPtrP = sStrTmpP;
     }

     if(iOvrFlg == 0){
        if(iSign == -1){                  /* check overflow */
           if(ulAllDat > (unsigned long)LONG_MIN){
              iOvrFlg = 1;                    /* - overflow */
           }
        }
        else {
           if(ulAllDat > (unsigned long)LONG_MAX){
              iOvrFlg = 1;                    /* + overflow */
           }
        }
     }

     if(iOvrFlg == 1){               /* dispose of overflow */
        errno = ERANGE;
        if(iSign == -1){
           return  (long)LONG_MIN;
        }
        else {
           return  (long)LONG_MAX;
        }
     }
                                  /* return converted value */ 
     return  (long)(ulAllDat*(long)iSign);
}


